package cn.mastercom.gui.hdfsExplorer.views;

import cn.mastercom.bigdata.util.hadoop.hdfs.DownloadAndUploadTask;
import cn.mastercom.bigdata.util.hadoop.hdfs.DownloadAndUploadTask.TaskType;
import cn.mastercom.gui.components.RowHeaderTable;
import cn.mastercom.gui.util.GuiUtil;
import cn.mastercom.sssvr.util.HdfsExplorerHelper;
import lombok.extern.log4j.Log4j;
import org.apache.log4j.Logger;

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Log4j
public class TabbedPane extends JTabbedPane implements Observer {
    private static final long serialVersionUID = 1L;

    private transient HdfsExplorerHelper helper;

    /**
     * 用于上传完成后刷新界面
     */
    private boolean needRefresh = false;

    private JScrollPane tableContainer;
    private JTable table;
    private JButton start;
    private JButton pause;
    private JButton suspend;
    private JButton selectAll;
    private JButton inverseSel;
    private JButton remove;
    private JProgressBar totalProgressBar;
    private DefaultTableModel tableModel;
    private LogArea consoleTextArea;
    private HashMap<Integer, DownloadAndUploadTask> dataModel;
    private transient ScheduledExecutorService pool;

    private TabbedPane() {
        this.pool = Executors.newScheduledThreadPool(1);
        this.table = new JTable();
        this.tableModel = initTableModel();
        this.table.setModel(tableModel);
        this.table.setDefaultRenderer(Object.class, initTableCellRenderer());
        this.table.setRowSorter(new TableRowSorter<TableModel>(tableModel));
        this.tableContainer = new JScrollPane(table);
        try {
            this.consoleTextArea = new LogArea();
        } catch (IOException e) {
            log.error(e);
        }
    }

    public TabbedPane(HdfsExplorerHelper helper) {
        this();
        this.dataModel = helper.getTaskMap();
        this.helper = helper;
        helper.addObserver(this);

        initUI();
        initLookAndFeel();

        addEventListener();
        addActionListener();

        run();
    }

    private void initUI() {
        JScrollPane scrollPanel = new JScrollPane(consoleTextArea);
        addTab("日志", null, scrollPanel, null);

        JPanel panel = new JPanel();
        addTab("任务详情", null, panel, null);
        panel.setLayout(new BorderLayout(0, 0));

        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        start = new JButton("继续");
        toolBar.add(start);
        pause = new JButton("暂停");
        toolBar.add(pause);
        suspend = new JButton("停止");
        toolBar.add(suspend);
        selectAll = new JButton("全选");
        toolBar.add(selectAll);
        inverseSel = new JButton("反选");
        toolBar.add(inverseSel);
        remove = new JButton("移除任务");
        toolBar.add(remove);
        totalProgressBar = new JProgressBar();
        toolBar.add(totalProgressBar);

        panel.add(toolBar, BorderLayout.NORTH);
        panel.add(tableContainer, BorderLayout.CENTER);
    }

    private void initLookAndFeel() {
        helper.initLookAndFeel();

        consoleTextArea.setEditable(false);
        consoleTextArea.setLineWrap(true);
        consoleTextArea.setFont(java.awt.Font.decode("宋体"));
        consoleTextArea.setText("");
        totalProgressBar.setStringPainted(true);
        GuiUtil.hideTableColumn(table, 0);
    }

    private void addActionListener() {
        final JPopupMenu popupText = new JPopupMenu();
        JMenuItem menuItem = new JMenuItem("清空");
        menuItem.addActionListener(e -> consoleTextArea.setText(""));
        popupText.add(menuItem);

        consoleTextArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(final MouseEvent e) {
                if (e.isPopupTrigger()) {
                    popupText.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
    }

    private void addEventListener() {
        start.addActionListener(e -> {
            int[] rows = table.getSelectedRows();
            for (int row : rows) {
                DownloadAndUploadTask task = getTaskAt(row);
                if (task != null) task.start();
            }
        });
        pause.addActionListener(e -> {
            int[] rows = table.getSelectedRows();
            for (int row : rows) {
                DownloadAndUploadTask task = getTaskAt(row);
                if (task != null) task.pause();
            }
        });
        suspend.addActionListener(e -> {
            int[] rows = table.getSelectedRows();
            for (int row : rows) {
                DownloadAndUploadTask task = getTaskAt(row);
                if (task != null) task.suspend();
            }
        });
        selectAll.addActionListener(e -> table.selectAll());
        inverseSel.addActionListener(e -> {
            List<Integer> tmp = new ArrayList<>();
            for (int i = 0; i < table.getRowCount(); i++) {
                if (!table.isRowSelected(i)) {
                    tmp.add(i);
                }
            }
            table.clearSelection();
            for (Integer i : tmp) {
                table.addRowSelectionInterval(i, i);
            }
        });
        remove.addActionListener(e -> {
            int[] rows = table.getSelectedRows();
            for (int row : rows) {
                DownloadAndUploadTask task = getTaskAt(row);
                // 必须先终止任务，之后才能移除任务
                if (task != null) task.suspend();
                dataModel.remove(getTaskKey(row));
            }
        });
    }

    private DefaultTableModel initTableModel() {
        return new DefaultTableModel(new Object[0][0],
                new String[]{"id", "任务类型", "文件名", "下载进度", "开始时间", "结束时间", "任务状态"}) {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
    }

    private DefaultTableCellRenderer initTableCellRenderer() {
        return new DefaultTableCellRenderer() {
            private static final long serialVersionUID = 1L;

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                           boolean hasFocus, int row, int column) {
                Component ret = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                // 第二列是任务类型
                if (column == 1
                        && value instanceof TaskType
                        && value == TaskType.UnknownType) {
                    this.setText("正在获取任务类型...");
                    return this;
                }
                // 第三列文件名
                if (column == 2
                        && ("".equals(value))) {
                    this.setText("正在获取文件名...");
                    return this;
                }
                // 第四列是进度信息
                if (column == 3
                        && value instanceof Integer) {
                    int progress = (Integer) value;
                    JProgressBar jBar = new JProgressBar();
                    jBar.setValue(progress);
                    jBar.setStringPainted(true);
                    jBar.setForeground(progress == 100 ? Color.GREEN : Color.BLUE);
                    return jBar;
                }
                // 第七列是状态信息
//                if (column == 6
//                        && !"".equals(value)) {
                // XXX：改变颜色，效果不好，暂时去掉
//                }

                if (value instanceof Date) {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss");
                    this.setText("-");
                    this.setText(format.format((Date) value));
                    return this;
                }
                return ret;
            }
        };
    }

    private int getTaskKey(int row) {
        if (row < 0 || row > tableModel.getRowCount()) {
            throw new IllegalArgumentException(this.getClass().getName() + ":无法找到第" + row + "行（从0开始）");
        }
        return Integer.parseInt(tableModel.getValueAt(row, 0).toString());
    }

    private DownloadAndUploadTask getTaskAt(int row) {
        if (row < 0 || row > tableModel.getRowCount()) {
            return null;
        }
        return dataModel.get(getTaskKey(row));
    }

    private Object[][] fu() {
        Object[][] ret = new Object[dataModel.size()][table.getColumnCount()];
        Set<Integer> keys = dataModel.keySet();
        int index = 0;
        for (Integer key : keys) {
            DownloadAndUploadTask task = dataModel.get(key);
            ret[index][0] = task.hashCode(); // key
            ret[index][1] = task.getTaskType(); // 任务类型
            ret[index][2] = task.getFileName(); // 文件名
            ret[index][3] = task.getProgress(); // 下载进度
            ret[index][4] = task.getStartDate(); // 开始时间
            ret[index][5] = task.getEndDate(); // 结束时间
            ret[index][6] = task.getStatus(); // 任务状态
            index++;
        }
        return ret;
    }

    private void updateTableCell() {
        int count = 0;    // 统计完成的任务数量
        for (int i = 0; i < tableModel.getRowCount(); i++) {
            Integer id = null;
            if (tableModel.getValueAt(i, 0) instanceof Integer) {
                id = (Integer) tableModel.getValueAt(i, 0);
            }
            DownloadAndUploadTask task = dataModel.get(id);
            task.getTaskInfo();
            // 更新任务类型
            tableModel.setValueAt(task.getTaskType(), i, 1);
            // 更新文件名
            tableModel.setValueAt(task.getFileName(), i, 2);
            // 更新进度条
            int progress = task.getProgress();
            tableModel.setValueAt(progress, i, 3);
            if (progress == 100) count++;
            // 更新任务结束时间
            tableModel.setValueAt(task.getEndDate(), i, 5);
            // 更新状态信息
            tableModel.setValueAt(task.getStatus(), i, 6);
        }
        totalProgressBar.setValue(count);

        // 只有需要刷新 且 进度条达到100% 且 进度条最大进度不为零才能刷新界面
        if (needRefresh && totalProgressBar.getValue() == totalProgressBar.getMaximum() && totalProgressBar.getMaximum() != 0) {
            totalProgressBar.setBackground(Color.GREEN);
            helper.refresh();
            needRefresh = false;
        } else
            totalProgressBar.setBackground(Color.BLUE);
    }

    private void run() {
        Runnable task = () -> {
            try {
                // 当dataModel数据量有变化时，重绘table
                if (tableModel.getRowCount() != dataModel.size()) {
                    tableContainer.setRowHeaderView(null);
                    tableModel.setRowCount(0);
                    Object[][] objects = fu();
                    for (Object[] rowData : objects) {
                        tableModel.addRow(rowData);
                    }

                    if (objects.length != 0)
                        tableContainer.setRowHeaderView(new RowHeaderTable(table));

                    totalProgressBar.setMinimum(0);
                    totalProgressBar.setMaximum(objects.length);

                    // 还有未完成的任务时才需要设置刷新
                    if (totalProgressBar.getValue() < totalProgressBar.getMaximum())
                        needRefresh = true;
                }
                // 否则，更新table单元格里的数据即可
                else
                    updateTableCell();
            } catch (Exception ignored) {
                // 确保该方法不会被异常打断
            }
        };
        pool.scheduleWithFixedDelay(task, 0, 200, TimeUnit.MILLISECONDS);
    }

    @Override
    public void update(Observable o, Object arg) {
        // 暂不实现
    }
}
